﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using EnvDTE80;
using EnvDTE;
using System.Threading;
using NRemedy;
using System.IO;
using VSLangProj;


namespace Wicresoft.NRemedy.VS10Addin.UI
{
    public partial class RemedyModelAdd : Form
    {
        private DTE2 _applicationObject = null;
        private AddIn _addin = null;

        private bool colum0;
        private bool colum1;
        private bool colum2;
        private bool colum3;
        private bool colum4;
        private bool colum5;

        private static string Server = string.Empty;
        private static string User = string.Empty;
        private static string Password = string.Empty;

        //Store NameLike
        private static string NameLike = string.Empty;
        //Cache FormList
        private static List<FormListItemData> formList = new List<FormListItemData>();

        public RemedyModelAdd(DTE2 _applicationObject, AddIn _addin)
        {
            if (_applicationObject == null)
                MessageBox.Show("Context Error : DTE2 interface cannot be null.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

            if (_addin == null)
                MessageBox.Show("Context Error : AddIn interface cannot be null.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

            this._applicationObject = _applicationObject;
            this._addin = _addin;

            InitializeComponent();

            this.pbar_Loading.Visible = false;

            if (Server == string.Empty || User == string.Empty || Password == string.Empty)
            {
                rmcg rmcg = LoadRMCG(Server);
                if (rmcg == null)
                {
                    MessageBox.Show("Error occur while loading .rmcg", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                else if (rmcg.Server == null
                    || string.IsNullOrEmpty(rmcg.Server.Server)
                    || string.IsNullOrEmpty(rmcg.Server.User)
                    || string.IsNullOrEmpty(rmcg.Server.Password))
                {
                    MessageBox.Show("Missing Server Info in rmcg", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                else
                {
                    Server = rmcg.Server.Server;
                    User = rmcg.Server.User;
                    Password = rmcg.Server.Password;
                }
            }

            txt_Server.Text = Server;
            txt_User.Text = User;
            txt_Password.Text = Password;

            if (formList.Count == 0)
            {
                LoadFormData();
            }
            else
            {
                RefereshListView();
            }


        }

        private void SetCurrentClassImportStatusByRMCG(rmcg rmcg)
        {
            if (rmcg.Server != null)
            {
                txt_User.Text = rmcg.Server.User;
                txt_Password.Text = rmcg.Server.Password;
                User = rmcg.Server.User;
                Password = rmcg.Server.Password;
            }

            List<FormListItemData> exist = new List<FormListItemData>();

            if (rmcg.Mappings != null)
            {
                foreach (var map in rmcg.Mappings)
                {
                    if (map.EntityTypeMapping != null
                        && !string.IsNullOrEmpty(map.EntityTypeMapping.TypeName))
                    {
                        if (map.EntityTypeMapping.MappingFragment != null
                            && !string.IsNullOrEmpty(map.EntityTypeMapping.MappingFragment.StoreEntitySet))
                        {
                            var item = formList.FirstOrDefault(f => f.FormName == map.EntityTypeMapping.TypeName);
                            if (item == null)
                                continue;
                            item.IsChecked = true;

                            if (item.PropertyMapping == null)
                                item.PropertyMapping = new List<ModelPropertyInfo>();
                            else
                                item.PropertyMapping.Clear();
                            if (map.EntityTypeMapping.MappingFragment.ScalarProperty == null)
                                continue;
                            foreach (var p in map.EntityTypeMapping.MappingFragment.ScalarProperty)
                            {
                                item.PropertyMapping.Add(new ModelPropertyInfo
                                {
                                    IsChecked = p.Mapped,
                                    ModelPropertyName = p.Name,
                                    RemedyFieldName = p.ColumnName
                                });

                            }
                        }
                    }
                }
            }
        }

        protected virtual void Loader_OnLoadCompeleted(List<string> data)
        {
            if (Server == string.Empty)
                return;
            rmcg rmcg = LoadRMCG(Server);


            formList.Clear();

            foreach (var d in data)
            {
                formList.Add(new FormListItemData
                {
                    IsChecked = false,
                    FormName = d
                });
            }

            if (rmcg != null)
                SetCurrentClassImportStatusByRMCG(rmcg);

            RefereshListView();
            ClientActive();
        }

        protected virtual void CodeLoader_OnGenerateCompeleted(List<ModelInfo> data)
        {
            Project proj = null;
            ProjectItems subItems = null;
            ProjectItem currentItem = null;
            if (!VSAddinUtil.TryGetCurrentSubItemsAndContainerProj(_applicationObject, ref subItems, ref proj, ref currentItem))
                return;
            string path = null;//file target full path
            if (currentItem != null)
                path = currentItem.Properties.Item("FullPath").Value.ToString();
            else
                path = proj.Properties.Item("FullPath").Value.ToString();

            rmcg rmcg = new rmcg();
            List<rmcgMapping> mappings = new List<rmcgMapping>();

            string rmcgfilePath = Path.Combine(path, Server.ToLower() + ".rmcg");
            ProjectItem rmcgItem = VSAddinUtil.GetProjectItemByName(Server.ToLower() + ".rmcg", subItems);

            //产生rmcg，写入空，并添加到工程中
            if (rmcgItem == null)
            {
                if (File.Exists(rmcgfilePath) && new FileInfo(rmcgfilePath).IsReadOnly)
                {
                    File.SetAttributes(rmcgfilePath, FileAttributes.Normal);
                }
                File.WriteAllText(rmcgfilePath, string.Empty);
                rmcgItem = subItems.AddFromFile(rmcgfilePath);
            }


            //先在磁盘上生成文件
            foreach (ModelInfo mi in data)
            {
                string filePath = Path.Combine(path, mi.ClassName + ".cs");
                if (File.Exists(filePath) && new FileInfo(filePath).IsReadOnly)
                    File.SetAttributes(filePath, FileAttributes.Normal);
                File.WriteAllText(filePath, mi.ModelCode);

                rmcgMapping mapping = new rmcgMapping();
                mapping.EntityTypeMapping = new rmcgMappingEntityTypeMapping();
                mapping.EntityTypeMapping.TypeName = mi.FormName;
                mapping.EntityTypeMapping.MappingFragment = new rmcgMappingEntityTypeMappingMappingFragment();
                mapping.EntityTypeMapping.MappingFragment.StoreEntitySet = mi.ClassName;

                List<rmcgMappingEntityTypeMappingMappingFragmentScalarProperty> properties
                    = new List<rmcgMappingEntityTypeMappingMappingFragmentScalarProperty>();

                if (mi.Properties != null)
                {
                    foreach (var p in mi.Properties)
                    {
                        properties.Add(new rmcgMappingEntityTypeMappingMappingFragmentScalarProperty
                        {
                            ColumnName = p.RemedyFieldName,
                            Name = p.ModelPropertyName,
                            Mapped = true
                        });
                    }

                    mapping.EntityTypeMapping.MappingFragment.ScalarProperty = properties.ToArray();
                }

                mappings.Add(mapping);

                //添加到工程中
                ProjectItem csItem = VSAddinUtil.GetProjectItemByName(mi.ClassName + ".cs", subItems);
                if (csItem == null)
                    rmcgItem.ProjectItems.AddFromFile(filePath);

            }

            rmcg.Version = "1.0";
            rmcg.Server = new rmcgServer();
            rmcg.Server.Server = Server;
            rmcg.Server.User = User;
            rmcg.Server.Password = Password;
            rmcg.Mappings = mappings.ToArray();

            File.WriteAllText(rmcgfilePath, Parser.CreateRMCGFile(rmcg));

            //添加引用
            string DllPath = _addin.SatelliteDllPath;
            string ErrorMessage = string.Empty;
            FileInfo fi = new FileInfo(DllPath);

            DirectoryInfo di = new DirectoryInfo(fi.DirectoryName);

            if (!File.Exists(Path.Combine(fi.Directory.Parent.FullName, "NRemedy.dll")))
                ErrorMessage = string.Format("NRemedy.dll could not be found in {0}.\n", DllPath);
            if (!File.Exists(Path.Combine(fi.Directory.Parent.FullName, "BMC.ARSystem.dll")))
                ErrorMessage = string.Format("BMC.ARSystem.dll could not be found in {0}.\n", DllPath);
            if (ErrorMessage != string.Empty)
                MessageBox.Show(ErrorMessage + "You may reference them manually in the current project.", "Missing dll", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            if (ErrorMessage == string.Empty)
            {
                VSProject vsProj = proj.Object as VSProject;
                try
                {
                    vsProj.References.Add(Path.Combine(fi.Directory.Parent.FullName, "NRemedy.dll"));
                    vsProj.References.Add(Path.Combine(fi.Directory.Parent.FullName, "BMC.ARSystem.dll"));
                }
                catch
                { }
            }

            //保存工程
            proj.Save();

            //SetCurrentClassImportStatus(this._applicationObject);
            //RefereshListView();
            ClientActive();
            this.Close();
        }

        private void SetCurrentPropertyImportStatusByRMCG(rmcg rmcg, List<ModelPropertyInfo> target, string formnName)
        {
            var entity = rmcg.Mappings.FirstOrDefault
                    (m => m.EntityTypeMapping != null && m.EntityTypeMapping.TypeName == formnName);
            if (entity == null) return;
            if (entity.EntityTypeMapping.MappingFragment != null)
            {
                if (entity.EntityTypeMapping.MappingFragment.ScalarProperty != null)
                {
                    foreach (var p in entity.EntityTypeMapping.MappingFragment.ScalarProperty)
                    {
                        var prop = target.FirstOrDefault(pr => pr.RemedyFieldName == p.ColumnName);
                        if (prop == null) continue;
                        prop.ModelPropertyName = p.Name;
                        prop.IsChecked = true;
                    }
                }
            }

        }

        protected virtual void FieldLoader_OnGenerateCompeleted(List<ModelPropertyInfo> data)
        {
            if (lvw_FormList.SelectedItems.Count > 0)
            {
                string selectedFormName = lvw_FormList.SelectedItems[0].SubItems[1].Text;

                var item = formList.FirstOrDefault(f => f.FormName == selectedFormName);

                if (item == null) return;

                if (Server == null) return;

                if (item.PropertyMapping != null)
                    item.PropertyMapping.Clear();
                item.PropertyMapping = data;

                rmcg rmcg = LoadRMCG(Server);
                if (rmcg != null)
                    SetCurrentPropertyImportStatusByRMCG(rmcg, item.PropertyMapping, selectedFormName);

                RefereshListView2(selectedFormName);
                ClientActive();
            }

        }

        private void btn_TestConnection_Click(object sender, EventArgs e)
        {
            Server = txt_Server.Text;
            User = txt_User.Text;
            Password = txt_Password.Text;
            NameLike = txt_NameLike.Text;

            try
            {
                ARLoginContext context = new ARLoginContext(Server, User, Password);
                ARSchema schema = new ARSchema(context);
                if (context.LoginStatus == ARLoginStatus.Success)
                {
                    MessageBox.Show("Connection Success!");
                    LoadFormData();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

        private void lvw_FormList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lvw_FormList.SelectedItems.Count > 0)
            {
                string selectedFormName = lvw_FormList.SelectedItems[0].SubItems[1].Text;

                var item = formList.FirstOrDefault(f => f.FormName == selectedFormName);

                if (item == null) return;

                LoadPropertyData(item);
            }
        }

        private void lvw_FormList_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            switch (e.Column)
            {
                case 0:
                    if (colum0)
                    {
                        formList = formList.OrderBy(f => f.IsChecked).ToList();
                        colum0 = false;
                    }
                    else
                    {
                        formList = formList.OrderByDescending(f => f.IsChecked).ToList();
                        colum0 = true;
                    }
                    break;
                case 1:
                    if (colum1)
                    {
                        formList = formList.OrderBy(f => f.FormName).ToList();
                        colum1 = false;
                    }
                    else
                    {
                        formList = formList.OrderByDescending(f => f.FormName).ToList();
                        colum1 = true;
                    }
                    break;
                default: break;
            }


            RefereshListView();
        }

        private void LoadFormData()
        {
            if (Server == string.Empty || User == string.Empty || Password == string.Empty)
            {
                MessageBox.Show("Parameter Missing", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            ClientLoading(new Point(82, 300));

            Loader loader = new Loader();
            loader.OnLoadCompeleted += new SendFormListDelegation(Loader_OnLoadCompeleted);
            loader.LoadFormList(Server, User, Password, NameLike);

        }

        private void LoadPropertyData(FormListItemData item)
        {
            if (item == null) return;
            //ever load in this session
            if (item.PropertyMapping == null || item.PropertyMapping.Count == 0)
            {
                ClientLoading(new Point(361, 240));
                FieldLoader loader = new FieldLoader();
                //FieldLoader_OnGenerateCompeleted
                loader.OnLoadCompeleted += new SendPropertyListDelegation(FieldLoader_OnGenerateCompeleted);
                loader.LoadProperties(Server, User, Password, item.FormName);
            }
            else
            {
                rmcg rmcg = LoadRMCG(Server);
                if (rmcg != null)
                    SetCurrentPropertyImportStatusByRMCG(rmcg, item.PropertyMapping, item.FormName);

                RefereshListView2(item.FormName);

            }
        }

        private void GenerateCode()
        {
            if (Server == string.Empty || User == string.Empty || Password == string.Empty)
            {
                MessageBox.Show("Parameter Missing", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }


            ClientLoading(new Point(223, 265));

            CodeLoader loader = new CodeLoader();
            loader.OnGenerateCompeleted += new SendModelListDelegation(CodeLoader_OnGenerateCompeleted);
            loader.GenerateCodes(Server, User, Password, formList);
        }

        private void RefereshListView()
        {
            this.lvw_FormList.Items.Clear();
            foreach (var fl in formList)
            {
                this.lvw_FormList.Items.Add(fl.ToListViewItem());
            }
        }

        private void RefereshListView2(string formName)
        {
            this.lvw_PropertyList.Items.Clear();

            var item = formList.FirstOrDefault(f => f.FormName == formName);

            if (item == null) return;

            if (item.PropertyMapping == null) return;

            foreach (var pm in item.PropertyMapping)
            {
                this.lvw_PropertyList.Items.Add(pm.ToListViewItem());
            }
        }

        private void reLoadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LoadFormData();
        }

        private void reLoadPropertyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (lvw_FormList.SelectedItems.Count > 0)
            {
                string selectedFormName = lvw_FormList.SelectedItems[0].SubItems[1].Text;

                var item = formList.FirstOrDefault(f => f.FormName == selectedFormName);

                if (item == null) return;

                item.PropertyMapping.Clear();

                LoadPropertyData(item);
            }
        }

        private void txt_NameLike_TextChanged(object sender, EventArgs e)
        {
            NameLike = txt_NameLike.Text;
        }

        private void txt_NameLike_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                LoadFormData();
            }
        }

        private void btn_OK_Click(object sender, EventArgs e)
        {
            GenerateCode();
        }

        private void ClientLoading(Point barLocation)
        {
            foreach (Control c in this.Controls)
            {
                if (c.Name != "pbar_Loading")
                    c.Enabled = false;
            }
            pbar_Loading.Location = barLocation;
            pbar_Loading.Visible = true;

        }

        private void ClientActive()
        {
            foreach (Control c in this.Controls)
            {
                if (c.Name != "pbar_Loading")
                    c.Enabled = true;
            }
            pbar_Loading.Visible = false;

        }

        private void lvw_PropertyList_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (lvw_FormList.SelectedItems.Count > 0)
            {
                string selectedFormName = lvw_FormList.SelectedItems[0].SubItems[1].Text;

                var item = formList.FirstOrDefault(f => f.FormName == selectedFormName);

                if (item == null) return;

                item.PropertyMapping[e.Index].IsChecked = (int)e.NewValue == 1;
            }
        }

        private void lvw_FormList_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            formList[e.Index].IsChecked = (int)e.NewValue == 1;
        }

        private rmcg LoadRMCG(string server)
        {
            Project proj = null;
            ProjectItems subItems = null;
            ProjectItem currentItem = null;
            ProjectItem rmcgItem = null;
            if (!VSAddinUtil.TryGetCurrentSubItemsAndContainerProj(_applicationObject, ref subItems, ref proj, ref currentItem))
                return null;
            if (subItems == null) return null;

            if (string.IsNullOrEmpty(server))
                rmcgItem = VSAddinUtil.GetFirstProjectItemLikeName(".rmcg", subItems);
            else
                rmcgItem = VSAddinUtil.GetProjectItemByName(server.ToLower() + ".rmcg", subItems);
            if (rmcgItem == null) return null;

            string rmcgPath = rmcgItem.Properties.Item("FullPath").Value.ToString();
            if (!File.Exists(rmcgPath))
            {
                MessageBox.Show("File may be deleted :" + rmcgPath, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return null;
            }
            try
            {
                string config = null;
                using (StreamReader sr = new StreamReader(rmcgPath, Encoding.Default, true))
                {
                    config = sr.ReadToEnd();
                }
                rmcg rmcg = Parser.CreateRMCGObject(config);
                return rmcg;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return null;
            }

        }

        private void lvw_PropertyList_ColumnClick(object sender, ColumnClickEventArgs e)
        {

            if (lvw_FormList.SelectedItems.Count == 0)
            {
                MessageBox.Show("Please select the form first");
                return;
            }
            string selectedFormName = lvw_FormList.SelectedItems[0].SubItems[1].Text;

            var item = formList.FirstOrDefault(f => f.FormName == selectedFormName);

            if (item == null) return;

            switch (e.Column)
            {
                case 0:
                    if (colum2)
                    {
                        item.PropertyMapping = item.PropertyMapping.OrderBy(f => f.IsChecked).ToList();
                        colum2 = false;
                    }
                    else
                    {
                        item.PropertyMapping = item.PropertyMapping.OrderByDescending(f => f.IsChecked).ToList();
                        colum2 = true;
                    }
                    break;
                case 1:
                    if (colum3)
                    {
                        item.PropertyMapping = item.PropertyMapping.OrderBy(f => Convert.ToInt32(f.RemedyFieldId)).ToList();
                        colum3 = false;
                    }
                    else
                    {
                        item.PropertyMapping = item.PropertyMapping.OrderByDescending(f => Convert.ToInt32(f.RemedyFieldId)).ToList();
                        colum3 = true;
                    }
                    break;
                case 2:
                    if (colum4)
                    {
                        item.PropertyMapping = item.PropertyMapping.OrderBy(f => f.RemedyFieldName).ToList();
                        colum4 = false;
                    }
                    else
                    {
                        item.PropertyMapping = item.PropertyMapping.OrderByDescending(f => f.RemedyFieldName).ToList();
                        colum4 = true;
                    }
                    break;
                case 3:
                    if (colum5)
                    {
                        item.PropertyMapping = item.PropertyMapping.OrderBy(f => f.ModelPropertyName).ToList();
                        colum5 = false;
                    }
                    else
                    {
                        item.PropertyMapping = item.PropertyMapping.OrderByDescending(f => f.ModelPropertyName).ToList();
                        colum5 = true;
                    }
                    break;
                default: break;
            }


            RefereshListView2(item.FormName);
        }

    }
}
